#tag Class
Protected Class PrefContainer
	#tag Method, Flags = &h1
		Protected Sub AppendValue(prefName as string, prefValue as string)
		  if not Exists(prefName) then
		    mPrefNames.Append prefName
		    mPrefValues.Append prefValue
		    mNumPrefs = mNumPrefs + 1
		  end
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Clear()
		  while NumPrefs() > 0
		    DeleteNth(0)
		  wend
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Constructor(prefFileName as String)
		  // Written by Steve LoBasso <slobasso@yahoo.com>
		  // Version 1.2
		  mFileName = prefFileName
		  mNumPrefs = 0
		  redim mPrefNames(-1)
		  redim mPrefValues(-1)
		  mScramblePrefix = "."
		  mScrambleKey = "scramble"
		  Clear()
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function DecodedChar(stringToDecode as string) As String
		  return(Chr(Val("&h" + Mid(stringToDecode, 2))))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Sub DecodePreference(prefEntry as string)
		  dim aPrefEntry as string
		  dim prefName as string
		  dim prefValue as string
		  
		  aPrefEntry = Trim(prefEntry)
		  if aPrefEntry <> "" and Left(aPrefEntry, 1) <> ";" and Left(aPrefEntry, 1) <> "#" and InStr(aPrefEntry, "=") <> 0 then
		    prefName = DecodeString(Trim(NthField(aPrefEntry, "=", 1)))
		    prefValue = DecodeString(Trim(Mid(aPrefEntry, InStr(aPrefEntry, "=") + 1)))
		    if Len(GetScramblePrefix()) <> 0 and Left(prefName, Len(GetScramblePrefix())) = GetScramblePrefix() then
		      prefValue = UnscrambleString(prefValue, GetScrambleKey())
		    end
		    Put(prefName, prefValue)
		  end
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function DecodeString(stringToDecode as string) As String
		  dim decodedString as string
		  dim escapePos as integer
		  dim startPos as integer
		  
		  decodedString = stringToDecode
		  startPos = 1
		  do
		    escapePos = InStr(Mid(decodedString, startPos), "%")
		    if escapePos <> 0 then
		      escapePos = escapePos + startPos - 1
		      decodedString = Left(decodedString, escapePos - 1) + DecodedChar(Mid(decodedString, escapePos, 3)) + Mid(decodedString, escapePos + 3)
		    end
		    startPos = escapePos + 1
		  loop until escapePos = 0
		  return(decodedString)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Delete(prefName as string)
		  DeleteNth(FindPrefIndex(prefName))
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Sub DeleteNth(prefIndex as integer)
		  if prefIndex >= 0 and prefIndex < NumPrefs() then
		    mPrefNames.Remove prefIndex
		    mPrefValues.Remove prefIndex
		    mNumPrefs = mNumPrefs - 1
		  end
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function EncodedChar(charToEncode as string) As String
		  return("%" + Right("00" + Hex(Asc(charToEncode)), 2))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function EncodePreference(prefIndex as integer) As String
		  dim prefName as string
		  dim prefValue as string
		  
		  prefName = GetNthName(prefIndex)
		  prefValue = GetNthValue(prefIndex)
		  if Len(GetScramblePrefix()) <> 0 and Left(prefName, Len(GetScramblePrefix())) = GetScramblePrefix() then
		    prefValue = ScrambleString(prefValue, GetScrambleKey())
		  end
		  return(EncodeString(prefName) + " = " + EncodeString(prefValue))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function EncodeString(stringToEncode as string) As String
		  dim encodedString as string
		  dim chrVal as integer
		  
		  encodedString = stringToEncode
		  encodedString = ReplaceAll(encodedString, "%", EncodedChar("%"))
		  encodedString = ReplaceAll(encodedString, "=", EncodedChar("="))
		  encodedString = ReplaceAll(encodedString, Chr(127), EncodedChar(Chr(127)))
		  for chrVal = 0 to 32
		    encodedString = ReplaceAll(encodedString, Chr(chrVal), EncodedChar(Chr(chrVal)))
		  next
		  return(encodedString)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function Exists(prefName as string) As Boolean
		  return(FindPrefIndex(prefName) >= 0)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function FindPrefIndex(prefName as string) As Integer
		  dim currPref as integer
		  dim foundPref as integer
		  
		  foundPref = -1
		  currPref = 0
		  while foundPref = -1 and currPref < NumPrefs()
		    if Uppercase(GetNthName(currPref)) = Uppercase(prefName) then
		      foundPref = currPref
		    end
		    currPref = currPref + 1
		  wend
		  return(foundPref)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function Get(prefName as string) As String
		  return(GetNthValue(FindPrefIndex(prefName)))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetBoolean(prefName as string) As Boolean
		  return(GetInteger(prefName) <> 0)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetColor(prefName as string) As Color
		  dim prefValue as string
		  
		  prefValue = GetString(prefName)
		  return(RGB(Val(NthField(prefValue, ",", 1)), Val(NthField(prefValue, ",", 2)), Val(NthField(prefValue, ",", 3))))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetDate(prefName as string) As Date
		  dim prefValue as Date
		  dim prefStr as string
		  
		  prefStr = GetString(prefName)
		  prefValue = new Date
		  prefValue.year = Val(NthField(prefStr, ",", 1))
		  prefValue.month = Val(NthField(prefStr, ",", 2))
		  prefValue.day = Val(NthField(prefStr, ",", 3))
		  prefValue.hour = Val(NthField(prefStr, ",", 4))
		  prefValue.minute = Val(NthField(prefStr, ",", 5))
		  prefValue.second = Val(NthField(prefStr, ",", 6))
		  prefValue.TotalSeconds = prefValue.TotalSeconds
		  return(prefValue)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetDouble(prefName as string) As Double
		  return(Val(GetString(prefName)))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetFolderItem(prefName as string) As FolderItem
		  dim f as folderitem
		  
		  f=GetFolderitem(GetString(prefName))
		  
		  return f
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetInteger(prefName as string) As Integer
		  return(Val(GetString(prefName)))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function GetNthName(prefIndex as integer) As String
		  dim prefName as string
		  
		  if prefIndex >= 0 and prefIndex < NumPrefs() then
		    prefName = mPrefNames(prefIndex)
		  else
		    prefName = ""
		  end
		  return(prefName)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function GetNthValue(prefIndex as integer) As String
		  dim prefValue as string
		  
		  if prefIndex >= 0 and prefIndex < NumPrefs() then
		    prefValue = mPrefValues(prefIndex)
		  else
		    prefValue = ""
		  end
		  return(prefValue)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetPrefFileName() As String
		  return(mFileName)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetScrambleKey() As String
		  return(mScrambleKey)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetScramblePrefix() As String
		  return(mScramblePrefix)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function GetString(prefName as string) As String
		  return(Get(prefName))
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function NumPrefs() As Integer
		  return(mNumPrefs)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function PrefLocation() As FolderItem
		  dim f as folderitem
		  dim s as string
		  
		  s=NthField(app.ExecutableFile.name,".",1)
		  
		  f=SpecialFolder.SharedApplicationData.Child(s)
		  if not f.exists then f.CreateAsFolder
		  
		  return(f)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Put(prefName as string, prefValue as string)
		  dim prefIndex as integer
		  
		  prefIndex = FindPrefIndex(prefName)
		  if prefIndex >= 0 then
		    SetNthValue(prefIndex, prefValue)
		  else
		    AppendValue(prefName, prefValue)
		  end
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub PutBoolean(prefName as string, prefValue as boolean)
		  if prefValue then
		    PutInteger(prefName, 1)
		  else
		    PutInteger(prefName, 0)
		  end
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub PutColor(prefName as string, prefValue as Color)
		  PutString(prefName, Str(prefValue.red) + "," + Str(prefValue.green) + "," + Str(prefValue.blue))
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub PutDate(prefName as string, prefValue as Date)
		  PutString(prefName, Str(prefValue.year)+","+Str(prefValue.month)+","+Str(prefValue.day)+","+Str(prefValue.hour)+","+Str(prefValue.minute)+","+Str(prefValue.second))
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub PutDouble(prefName as string, prefValue as double)
		  PutString(prefName, Str(prefValue))
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub PutFolderItem(prefName as string, prefValue as FolderItem)
		  PutString(prefName, prefValue.AbsolutePath)
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub PutInteger(prefName as string, prefValue as integer)
		  PutString(prefName, Format(prefValue, "###################;-###################;0"))
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub PutString(prefName as string, prefValue as string)
		  Put(prefName, prefValue)
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub Read()
		  Dim inFile As TextInputStream
		  
		  if GetPrefFileName() <> "" then
		    inFile = PrefLocation().Child(GetPrefFileName()).OpenAsTextFile
		    if inFile <> nil then
		      while not inFile.EOF
		        DecodePreference(inFile.ReadLine())
		      wend
		      inFile.Close()
		    end
		  end
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function ScrambleString(stringToScramble as string, key as string) As String
		  dim scrambledString as string
		  dim scrambledChar as string
		  dim keyChar as string
		  dim charPos as integer
		  dim x0, x1 as integer
		  dim p0, p1 as integer
		  
		  if Len(key) = 0 then
		    scrambledString = stringToScramble
		  else
		    scrambledString = ""
		    charPos = 1
		    while charPos <= Len(stringToScramble)
		      keyChar = Mid(key, (((charPos - 1) mod Len(key)) + 1), 1)
		      p0 = Asc(keyChar) mod 11
		      x0 = ((Asc(Mid(key, (((charPos + p0 - 1) mod Len(key)) + 1), 1)) * 11) + 13) mod 256
		      p1 = Asc(keyChar) mod 13
		      x1 = ((Asc(Mid(key, (((charPos + p1 - 1) mod Len(key)) + 1), 1)) * 17) + 19) mod 256
		      scrambledChar = Mid(stringToScramble, charPos, 1)
		      scrambledChar = Chr((Asc(scrambledChar) + x0 + x1) mod 256)
		      scrambledChar = Chr(BitwiseXor(Asc(keyChar), Asc(scrambledChar)))
		      scrambledString = scrambledString + scrambledChar
		      charPos = charPos + 1
		    wend
		  end
		  return(scrambledString)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Sub SetNthValue(prefIndex as integer, prefValue as string)
		  if prefIndex >= 0 and prefIndex < NumPrefs() then
		    mPrefValues(prefIndex) = prefValue
		  end
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub SetPrefFileName(theFileName as string)
		  mFileName = theFileName
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub SetScrambleKey(scrambleKey as string)
		  mScrambleKey = scrambleKey
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub SetScramblePrefix(scramblePrefix as string)
		  mScramblePrefix = scramblePrefix
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h1
		Protected Function UnscrambleString(stringToUnscramble as string, key as string) As String
		  dim unscrambledString as string
		  dim unscrambledChar as string
		  dim keyChar as string
		  dim charPos as integer
		  dim x0, x1 as integer
		  dim p0, p1 as integer
		  
		  if Len(key) = 0 then
		    unscrambledString = stringToUnscramble
		  else
		    unscrambledString = ""
		    charPos = 1
		    while charPos <= Len(stringToUnscramble)
		      keyChar = Mid(key, (((charPos - 1) mod Len(key)) + 1), 1)
		      unscrambledChar = Mid(stringToUnscramble, charPos, 1)
		      unscrambledChar = Chr(BitwiseXor(Asc(keyChar), Asc(unscrambledChar)))
		      p0 = Asc(keyChar) mod 11
		      x0 = ((Asc(Mid(key, (((charPos + p0 - 1) mod Len(key)) + 1), 1)) * 11) + 13) mod 256
		      p1 = Asc(keyChar) mod 13
		      x1 = ((Asc(Mid(key, (((charPos + p1 - 1) mod Len(key)) + 1), 1)) * 17) + 19) mod 256
		      unscrambledChar = Chr((Asc(unscrambledChar) + (256 - x0) + (256 - x1)) mod 256)
		      unscrambledString = unscrambledString + unscrambledChar
		      charPos = charPos + 1
		    wend
		  end
		  return(unscrambledString)
		End Function
	#tag EndMethod

	#tag Method, Flags = &h0
		Function Write() As boolean
		  dim prefFile as folderitem
		  dim outFile As TextOutputStream
		  dim prefIndex as integer
		  
		  if GetPrefFileName() <> "" then
		    prefFile = PrefLocation().Child(GetPrefFileName())
		    prefFile.Delete()
		    outFile = prefFile.CreateTextFile
		    if outFile <> nil then
		      prefIndex = 0
		      while prefIndex < NumPrefs()
		        outFile.WriteLine(EncodePreference(prefIndex))
		        prefIndex = prefIndex + 1
		      wend
		      outFile.Close()
		    end
		  end
		  
		  return true
		End Function
	#tag EndMethod


	#tag Property, Flags = &h1
		Protected mFileName As string
	#tag EndProperty

	#tag Property, Flags = &h1
		Protected mNumPrefs As integer
	#tag EndProperty

	#tag Property, Flags = &h1
		Protected mPrefNames(0) As string
	#tag EndProperty

	#tag Property, Flags = &h1
		Protected mPrefValues(0) As string
	#tag EndProperty

	#tag Property, Flags = &h1
		Protected mScrambleKey As string
	#tag EndProperty

	#tag Property, Flags = &h1
		Protected mScramblePrefix As string
	#tag EndProperty


	#tag ViewBehavior
		#tag ViewProperty
			Name="Index"
			Visible=true
			Group="ID"
			InitialValue="2147483648"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Left"
			Visible=true
			Group="Position"
			InitialValue="0"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Name"
			Visible=true
			Group="ID"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Super"
			Visible=true
			Group="ID"
			InheritedFrom="Object"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Top"
			Visible=true
			Group="Position"
			InitialValue="0"
			InheritedFrom="Object"
		#tag EndViewProperty
	#tag EndViewBehavior
End Class
#tag EndClass
